package cn.changein.framework.service.setting.area.impl;

import cn.changein.framework.base.pojo.page.PageFactory;
import cn.changein.framework.base.pojo.page.PageInfo;
import cn.changein.framework.constant.AreaConstants;
import cn.changein.framework.elasticsearch.util.JsonUtil;
import cn.changein.framework.model.setting.area.entity.Area;
import cn.changein.framework.model.setting.area.mapper.AreaMapper;
import cn.changein.framework.model.setting.area.model.params.AreaParam;
import cn.changein.framework.model.setting.area.model.result.AreaChain;
import cn.changein.framework.model.setting.area.model.result.AreaResult;
import cn.changein.framework.model.setting.area.model.result.ListTreeResult;
import cn.changein.framework.service.setting.area.AreaService;
import cn.changein.framework.util.ToolUtil;
import cn.changein.framework.util.beantools.Copier;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 地区表 服务实现类
 * </p>
 *

 * @Date 2020-12-15
 * @Copyright: companyName
 * @Version 1.0
 * @Since JDK1.8
 */
@Service
@Slf4j
public class AreaServiceImpl extends ServiceImpl<AreaMapper, Area> implements AreaService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void add(AreaParam param) {
        Area entity = getEntity(param);
        this.save(entity);
        Long id = entity.getId();
        this.clearAreaRedisCache();  //清空区域缓存信息
        param.setId(id);
    }

    @Override
    public void delete(AreaParam param) {
        this.removeById(getKey(param));
        this.clearAreaRedisCache(); //清空区域缓存信息
    }

    @Override
    public void update(AreaParam param) {
        Area oldEntity = getOldEntity(param);
        Area newEntity = getEntity(param);
        ToolUtil.copyProperties(newEntity, oldEntity);
        this.updateById(newEntity);
        this.clearAreaRedisCache(); //清空区域缓存信息
    }

    @Override
    public AreaResult findBySpec(AreaParam param) {
        return null;
    }

    @Override
    public List<AreaResult> findListBySpec(AreaParam param) {
        return null;
    }

    @Override
    public PageInfo adminFindPageBySpec(AreaParam param) {
        Page pageContext = param.getPage() != null || param.getLimit() != null ? new Page(param.getCorrectPage(), param.getCorrectLimit()) : getPageContext();
        IPage page = this.baseMapper.customPageList(pageContext, param);
        return PageFactory.createPageInfo(page);
    }

    @Override
    public List<Area> findByParentId(Long parentId) {
        return this.baseMapper.findByParentId(parentId);
    }

    /**
     * @Description: 获取所有地区数据
     * @Date:2020/12/16 18:12
     * @Param: [areaParam]

     */
    @Override
    public List<AreaResult> findListAllByAreaParam(AreaParam areaParam) {
        String adminAreaListKey = AreaConstants.ADMIN_AREA_LIST_KEY;
        if (this.redisTemplate.hasKey(adminAreaListKey)) {
            String areaListStr = (String) this.redisTemplate.opsForValue().get(adminAreaListKey);
            List<AreaResult> areaResults = JsonUtil.parseArray(areaListStr, AreaResult.class);
            return areaResults;
        }
        List<AreaResult> listAll = this.baseMapper.findListAllByAreaParam(areaParam);
        this.redisTemplate.boundValueOps(adminAreaListKey).set(JsonUtil.toJson(listAll));
        return listAll;
    }

    /**
     * @Description: 输出树形地区的数据
     * @Date:2020/12/16 18:11
     * @Param: [areaParam]

     */
    @Override
    public List<ListTreeResult> findListTreeInfo(AreaParam areaParam) {
        String parentId = "1";
        String adminAreaMapKey = AreaConstants.ADMIN_AREA_MAP_KEY;
        //存储地区数据
        Map<String, List<AreaResult>> grepMap = new HashMap<String, List<AreaResult>>();
        List<AreaResult> provinceList = Lists.newArrayList();
        if (!this.redisTemplate.hasKey(adminAreaMapKey)) {
            List<AreaResult> listAll = this.findListAllByAreaParam(areaParam);
            //分组
            grepMap = listAll.stream().collect(Collectors.groupingBy(AreaResult::getParentId));
            this.redisTemplate.boundValueOps(adminAreaMapKey).set(JsonUtil.toJson(grepMap)); //设置值
        } else {
            //通过ValueOperations获取值
            String strGrepMap = (String) this.redisTemplate.opsForValue().get(adminAreaMapKey);
            grepMap = JsonUtil.parseMap(strGrepMap, AreaResult.class);
        }
        provinceList = grepMap.get(parentId);
        /**用于输出地区的数据*/
        List<ListTreeResult> listTreeResults = new ArrayList<ListTreeResult>();
        //省
        for (AreaResult province : provinceList) {
            ListTreeResult treeResult = new ListTreeResult();
            Long provinceId = province.getId();
            treeResult.setId(provinceId);
            treeResult.setTitle(province.getFullName());

            listTreeResults.add(treeResult);

            if (!grepMap.containsKey(String.valueOf(provinceId))) continue;

            //获取市
            List<ListTreeResult.ListTreeChildrenResult> cityResultList = Lists.newArrayList();
            cityResultList = getListTreeChildrenResults(String.valueOf(provinceId), cityResultList, grepMap);
            treeResult.setChildren(cityResultList);
        }
        return listTreeResults;
    }


    @Override
    public AreaChain findAreaChain(AreaParam areaParam) {
        List<Area> allProvince = findByParent(1L);
        Area areaProvince = areaParam.getProvinceId() != null ? super.getById(areaParam.getProvinceId()) : null;
        Area areaDistrict = areaParam.getAreaId() != null ? super.getById(areaParam.getAreaId()) : null;
        Area areaCity = areaParam.getCityId() != null ? super.getById(areaParam.getCityId()) : null;

        List<Area> allCity = areaProvince != null ? findByParent(areaProvince.getId()) : Lists.newArrayList();
        List<Area> allDistrict = areaCity != null ? findByParent(areaCity.getId()) : Lists.newArrayList();

        List<AreaResult> provinceList = allProvince.stream().map(area -> {
            AreaResult province = Copier.copy(area, new AreaResult());
            if (areaProvince != null) {
                province.setSelected(province.getId().equals(areaProvince.getId()));
            }
            return province;
        }).collect(Collectors.toList());

        List<AreaResult> cityList = allCity.stream().map(area -> {
            AreaResult city = Copier.copy(area, new AreaResult());
            if (areaCity != null) {
                city.setSelected(city.getId().equals(areaCity.getId()));
            }
            return city;
        }).collect(Collectors.toList());


        List<AreaResult> districtList = allDistrict.stream().map(area -> {
            AreaResult district = Copier.copy(area, new AreaResult());
            if (areaDistrict != null) {
                district.setSelected(district.getId().equals(areaDistrict.getId()));
            }

            return district;
        }).collect(Collectors.toList());

        AreaChain areaChain = new AreaChain();
        areaChain.setProvinceList(provinceList);
        areaChain.setCityList(cityList);
        areaChain.setDistrictList(districtList);
        return areaChain;
    }

    @Override
    public List<Area> findByParent(long parentId) {
        QueryWrapper<Area> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Area::getParentId, parentId);
        return super.list(wrapper);
    }

    /**
     * @Description: 封装市和区用于输出
     * @Date:2020/12/16 16:47
     * @Param: [parentId, cityResultList, parentMap]

     */
    private List<ListTreeResult.ListTreeChildrenResult> getListTreeChildrenResults(String parentId, List<ListTreeResult.ListTreeChildrenResult> cityResultList, Map<String, List<AreaResult>> parentMap) {

        List<AreaResult> cityList = parentMap.get(parentId);
        if (CollectionUtils.isEmpty(cityList)) {
            return cityResultList;
        }
        for (AreaResult city : cityList) {

            ListTreeResult.ListTreeChildrenResult cityResult = new ListTreeResult.ListTreeChildrenResult();
            Long cityId = city.getId();
            String cityFullName = city.getFullName();
            cityResult.setId(cityId);
            cityResult.setTitle(cityFullName);

            cityResultList.add(cityResult);

            String cityIdStr = String.valueOf(cityId);

            /**获取区*/
            List<AreaResult> districtList = parentMap.get(cityIdStr);
            if (!parentMap.containsKey(cityIdStr)) continue;
            List<ListTreeResult.ListTreeChildrenResult> districtResultList = Lists.newArrayList();
            for (AreaResult district : districtList) {
                ListTreeResult.ListTreeChildrenResult districtResult = new ListTreeResult.ListTreeChildrenResult();
                Long districtId = district.getId();
                String districtFullName = district.getFullName();
                districtResult.setId(districtId);
                districtResult.setTitle(districtFullName);
                districtResultList.add(districtResult);
            }
            cityResult.setChildren(districtResultList);
        }
        return cityResultList;
    }

    private Serializable getKey(AreaParam param) {
        return param.getId();
    }

    private Page getPageContext() {
        return PageFactory.defaultPage();
    }

    private Area getOldEntity(AreaParam param) {
        return this.getById(getKey(param));
    }

    private Area getEntity(AreaParam param) {
        Area entity = new Area();
        ToolUtil.copyProperties(param, entity);
        return entity;
    }

    /**
     * @Description: 清空区域缓存信息
     * @Date:2020/12/19 15:31
     * @Param: []

     */
    @Override
    public void clearAreaRedisCache() {
        String apiAreaMapKey = AreaConstants.API_AREA_MAP_KEY;
        String adminAreaMapKey = AreaConstants.ADMIN_AREA_MAP_KEY;
        String adminAreaListKey = AreaConstants.ADMIN_AREA_LIST_KEY;
        if (this.redisTemplate.hasKey(apiAreaMapKey)) {
            this.redisTemplate.delete(apiAreaMapKey);
        }
        if (this.redisTemplate.hasKey(adminAreaMapKey)) {
            this.redisTemplate.delete(adminAreaMapKey);
        }
        if (this.redisTemplate.hasKey(adminAreaListKey)) {
            this.redisTemplate.delete(adminAreaListKey);
        }
    }

    /**
     * @Description: 获取省市 区
     * @Date:2020/12/19 14:48
     * @Param: [areaParam]

     */
    @Override
    public List<AreaResult> findByParentId(AreaParam areaParam) {
        Map<String, List<AreaResult>> grepMap = new HashMap<String, List<AreaResult>>();
        String areaMapKey = AreaConstants.API_AREA_MAP_KEY;
        String parentId = areaParam.getParentId();
        if (this.redisTemplate.hasKey(areaMapKey)) { //存在取缓存
            //通过ValueOperations获取值
            String strGrepMap = (String) this.redisTemplate.opsForValue().get(areaMapKey);

            grepMap = JsonUtil.parseMap(strGrepMap, AreaResult.class);
            List<AreaResult> areaResults = grepMap.get(parentId);
            if (CollectionUtils.isEmpty(areaResults)) {
                areaResults = Lists.newArrayList();
            }
            return areaResults;
        }

        List<AreaResult> listAll = this.findListAllByAreaParam(areaParam);
        //根据上级Id分组
        grepMap = listAll.stream().collect(Collectors.groupingBy(AreaResult::getParentId));
        List<AreaResult> areaResults = Optional.ofNullable(grepMap.get(parentId)).orElse(Lists.newArrayList());
        this.redisTemplate.boundValueOps(areaMapKey).set(JsonUtil.toJson(grepMap));
        return areaResults;
    }

    @Override
    public PageInfo findPageBySpec(AreaParam param) {
        Page pageContext = getPageContext();
        IPage page = this.baseMapper.customPageList(pageContext, param);
        return PageFactory.createPageInfo(page);
    }

}
